package com.zgw.fireline.design.Model;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.wb.core.model.JavaInfo;
import org.eclipse.wb.core.model.ObjectInfo;
import org.eclipse.wb.internal.core.model.JavaInfoUtils;
import org.eclipse.wb.internal.core.model.ObjectInfoVisitor;
import org.eclipse.wb.internal.core.model.creation.MethodParameterCreationSupport;
import org.eclipse.wb.internal.core.utils.ast.AstEditor;
import org.eclipse.wb.internal.core.utils.ast.AstNodeUtils;
import org.eclipse.wb.internal.core.utils.ast.BodyDeclarationTarget;
import org.eclipse.wb.internal.core.utils.ast.DomGenerics;
import org.eclipse.wb.internal.core.utils.ast.StatementTarget;
import org.eclipse.wb.internal.core.utils.check.Assert;
import org.eclipse.wb.internal.core.utils.execution.ExecutionUtils;
import org.eclipse.wb.internal.core.utils.execution.RunnableEx;
import org.eclipse.wb.internal.core.utils.execution.RunnableObjectEx;
import org.eclipse.wb.internal.core.utils.reflect.ReflectionUtils;
import org.eclipse.wb.internal.core.utils.state.GlobalState;
import org.eclipse.wb.internal.swt.model.widgets.WidgetInfo;

/**
 * 数据集编码工具集
 * */
public class DatasetCodeUtil {
	/**
	 * 根据属性列获取指定类型的值
	 * */
	public static final String GET_VALUE = "getValue";
	/**
	 * 根据属性列表达示获取字符串
	 * */
	public static final String GET_STRINGFOR_EXPR = "getStringForExpr";

	/**
	 * 用户环境中统一赋值的方法
	 * */
	public static final String SET_VALUES = "setValues";

	/**
	 * 用户环境中统一设置参数的方法
	 * */
	public static final String SET_PARAMS = "setParams";

	public static final String CREATE_BATCH_ITEM = "createBatchItem";

	// 创建界面之后
	public static final String CREATE_GUI_AFTER = "createGUIAfter";

	// 创建界面 之前
	public static final String CREATE_GUI_BEFORE = "createGUIBefore";

	/**
	 * 构建 统一赋值的环境 即添加 setValue 方法
	 * 
	 * @param root
	 * */
	public final static MethodDeclaration buildSetValuesContext(JavaInfo root)
			throws Exception {
		String signature = ReflectionUtils.getMethodSignature("setValues");
		MethodDeclaration initMethod = JavaInfoUtils // 界面内容创建 初始化方法
				.getMethodDeclaration(getFirstWidgetInfo(root));
		try {
			MethodDeclaration method = addMethod(root, signature);
			// ------------在界面初始化方法结尾处调用setValues方法
			addMethodInvocation(root.getEditor(), signature, initMethod, false);
			return method;
		} catch (Exception e) {
			throw ReflectionUtils.propagate(e);
		}
	}

	/**
	 * 构建设置参数的方法
	 * 
	 * @throws Exception
	 * */
	public static MethodDeclaration buildSetParamsContext(JavaInfo root)
			throws Exception {
		String signature = ReflectionUtils.getMethodSignature("setParams");
		MethodDeclaration initMethod = JavaInfoUtils // 界面内容创建 初始化方法
				.getMethodDeclaration(getFirstWidgetInfo(root));
		try {
			MethodDeclaration method = addMethod(root, signature);
			// ------------在界面初始化方法结尾处调用setParams方法
			addMethodInvocation(root.getEditor(), signature, initMethod, false);
			return method;
		} catch (Exception e) {
			throw ReflectionUtils.propagate(e);
		}
	}

	public static MethodDeclaration buildCreateGUIBeforeMethod(
			final JavaInfo root) {
		final String signature = ReflectionUtils
				.getMethodSignature("createGUIBefore");
		MethodDeclaration initMethod = JavaInfoUtils // 获取界面内容创建 初始化方法
				.getMethodDeclaration(getFirstWidgetInfo(root));
		try {
			MethodDeclaration method = addMethod(root, signature);
			// ------------在界面初始化方法结尾处调用createGUIAfter方法
			addMethodInvocation(root.getEditor(), signature, initMethod, true);
			return method;
		} catch (Exception e) {
			throw ReflectionUtils.propagate(e);
		}
	}

	public static MethodDeclaration buildCreateGUIAfterMethod(JavaInfo root) {
		final String signature = ReflectionUtils
				.getMethodSignature("createGUIAfter");
		MethodDeclaration initMethod = JavaInfoUtils // 界面内容创建 初始化方法
				.getMethodDeclaration(getFirstWidgetInfo(root));
		try {
			MethodDeclaration method = addMethod(root, signature);
			// ------------在界面初始化方法结尾处调用createGUIAfter方法
			addMethodInvocation(root.getEditor(), signature, initMethod, false);
			return method;
		} catch (Exception e) {
			throw ReflectionUtils.propagate(e);
		}
	}

	/**
	 * 添加一个方法
	 * 
	 * @param target2
	 * @throws Exception
	 * */
	private static MethodDeclaration addMethod(JavaInfo root, String signature)
			throws Exception {
		TypeDeclaration declaration = JavaInfoUtils.getTypeDeclaration(root);
		MethodDeclaration method = AstNodeUtils.getMethodBySignature(
				declaration, signature);
		AstEditor editor = root.getEditor();
		if (method == null) {
			BodyDeclarationTarget target = new BodyDeclarationTarget(
					declaration, null, false);
			method = editor.addMethodDeclaration(
					"protected  void " + signature, new ArrayList<String>(),
					target);
		}
		return method;
	}

	private static void addMethodInvocation(AstEditor edit, String signature,
			MethodDeclaration targetMethod, boolean beginning) throws Exception {
		List<Statement> statements = DomGenerics.statements(targetMethod
				.getBody());
		Statement call = null;
		for (Statement s : statements) {
			if (s.toString().trim().equals(signature + ";")) {
				call = s;
				break;
			}
		}
		if (call == null) {
			final StatementTarget target;
			if (beginning) {
				target = new StatementTarget(targetMethod, true);
			} else if (statements.isEmpty()) {
				target = new StatementTarget(targetMethod, false);
			} else {
				Statement last = statements.get(statements.size() - 1);
				target = new StatementTarget(last,
						last instanceof ReturnStatement);
			}
			edit.addStatement(signature + ";", target);
		}
	}

	/**
	 * 准备 IdataBaseProvide 赋值 源码
	 * */
	public static String prepareDBInvokeSource(Class<?> dbClass,
			TypeDeclaration typeDeclaration, AstEditor editor) throws Exception {

		// 使用实列 (INSTANCE)
		Field ins = ReflectionUtils.getFieldByName(dbClass, "INSTANCE");
		if (ins != null && ReflectionUtils.isPublic(ins)) {
			Object obj = ReflectionUtils.getFieldObject(dbClass, "INSTANCE");
			if (obj != null && obj.getClass().equals(dbClass)) {
				String source = dbClass.getName() + ".INSTANCE";
				return source;
			}
		}
		Method method = ReflectionUtils.getMethodByName(dbClass, "getInstance");

		// 静态方法获取实列
		Class<?> cla1 = GlobalState.getClassLoader().loadClass(
				"com.zgw.fireline.base.IDataBaseProvide");
		if (method != null && cla1.isAssignableFrom(method.getReturnType())
				&& Modifier.isStatic(method.getModifiers())
				&& Modifier.isPublic(method.getModifiers())) {
			String source = dbClass.getName() + ".getInstance()";
			return source;
		}

		// check create context field
		for (FieldDeclaration field : typeDeclaration.getFields()) {
			Type type = field.getType();
			if (type == null || AstNodeUtils.getTypeBinding(type) == null) {
				continue;
			}
			//
			String fieldType = AstNodeUtils.getFullyQualifiedName(type, false);
			//
			if (dbClass.getName().equals(fieldType)) {
				Assert.equals(1, field.fragments().size());
				VariableDeclarationFragment fragment = DomGenerics.fragments(
						field).get(0);
				return fragment.getName().getIdentifier();
			}
		}
		String cname = dbClass.getName();
		String var = dbClass.getSimpleName().toLowerCase();
		// create context field
		BodyDeclarationTarget fieldTarget = new BodyDeclarationTarget(
				typeDeclaration, null, true);
		editor.addFieldDeclaration("private final " + cname + " " + var
				+ " =new " + cname + "();", fieldTarget);
		return var;
	}

	// /**
	// * 根据AST 节点 查找java 模型
	// * */
	// public static JavaInfo getJavaInfoByASTNode(final ObjectInfo root,
	// ASTNode node) {
	// Assert.isTrue(root.isRoot());
	// final FindJavaInfo find = new FindJavaInfo(node);
	// ExecutionUtils.runLog(new RunnableEx() {
	// public void run() throws Exception {
	// root.accept0(find);
	// }
	// });
	// return find.result;
	// }
	//
	// private static class FindJavaInfo extends ObjectInfoVisitor {
	// public JavaInfo result;
	// private ASTNode node;
	//
	// public FindJavaInfo(ASTNode node) {
	// this.node = node;
	// }
	//
	// @Override
	// public boolean visit(ObjectInfo o) throws Exception {
	// if (o instanceof JavaInfo) {
	// for (ASTNode n : ((JavaInfo) o).getRelatedNodes()) {
	// if (n == node || n.getParent() == node) {
	// result = (JavaInfo) o;
	// return false;
	// }
	// }
	// }
	// return true;
	// }
	// }

	/**
	 * 将java 对象转换成源代码
	 * <p>
	 * <b>仅限以下数据类型:</b>
	 * <ul>
	 * <li><code>String</code></li>
	 * <li><code>Integer</code></li>
	 * <li><code>Lang</code></li>
	 * <li><code>Double</code></li>
	 * <li><code>Boolean</code></li>
	 * </ul>
	 * </p>
	 * */
	public static String objectToCode(Object obj) {
		if (obj instanceof Integer) {
			return String.valueOf(obj);
		} else if (obj instanceof Long) {
			return String.valueOf(obj) + "L";
		} else if (obj instanceof Double) {
			return String.valueOf(obj) + "D";
		} else if (obj instanceof Boolean) {
			return String.valueOf(obj);
		} else if (obj instanceof String) {
			return "\"" + String.valueOf(obj) + "\"";
		} else if (obj == null) {
			return "null";
		}
		return null;
	}

	public static JavaInfo getLastWidgetInfo(JavaInfo root) {
		class Visitor extends ObjectInfoVisitor {
			public JavaInfo lastInfo;

			@Override
			public boolean visit(ObjectInfo objectInfo) throws Exception {
				if (objectInfo instanceof WidgetInfo) {
					WidgetInfo widgetInfo = (WidgetInfo) objectInfo;
					lastInfo = widgetInfo;
				}
				return true;
			}
		}
		Visitor visitor = new Visitor();
		try {
			root.accept0(visitor);
		} catch (Exception e) {
			throw ReflectionUtils.propagate(e);
		}
		return visitor.lastInfo;
	}

	public static JavaInfo getFirstWidgetInfo(JavaInfo root) {
		class Visitor extends ObjectInfoVisitor {
			public JavaInfo firstInfo;

			@Override
			public boolean visit(ObjectInfo objectInfo) throws Exception {
				if (objectInfo instanceof WidgetInfo) {
					WidgetInfo widget = (WidgetInfo) objectInfo;
					if (!(widget.getCreationSupport() instanceof MethodParameterCreationSupport)) {
						firstInfo = widget;
						return false;
					}
				}
				return true;
			}
		}
		Visitor visitor = new Visitor();
		try {
			root.accept0(visitor);
		} catch (Exception e) {
			throw ReflectionUtils.propagate(e);
		}
		return visitor.firstInfo;
	}

	/**
	 * 获取第一个 Widget 创建之前的代码位置
	 * */
	public static StatementTarget getFistWidgetTarget(JavaInfo root) {
		StatementTarget target;
		try {
			target = JavaInfoUtils.getNodeTarget_beforeCreation(
					getFirstWidgetInfo(root)).getStatementTarget();
		} catch (Exception e) {
			throw ReflectionUtils.propagate(e);
		}
		return target;
	}
}
